
/* Copyright (c) Mark J. Kilgard, 1994. */

/* This program is freely distributable without licensing fees 
   and is provided without guarantee or warrantee expressed or 
   implied. This program is -not- in the public domain. */

#include <string.h>
#include <GL/glut.h>

enum {
  DL_BOGUS = 0,
  DL_MSG1,
  DL_MSG2,
  DL_MSG3
};

void *font = GLUT_BITMAP_TIMES_ROMAN_24;
void *fonts[] =
{
  GLUT_BITMAP_9_BY_15,
  GLUT_BITMAP_TIMES_ROMAN_10,
  GLUT_BITMAP_TIMES_ROMAN_24
};
char defaultMessage[] = "GLUT means OpenGL.";
char *message = defaultMessage;

void
output(int x, int y, char *string)
{
  int len, i;

  glRasterPos2f(x, y);
  len = (int) strlen(string);
  for (i = 0; i < len; i++) {
    glutBitmapCharacter(font, string[i]);
  }
}

void
updateDisplayLists(int updateAll)
{
  /* Calling glutBitmapCharacter is more expensive than you
     might think since it has to ensure that the right
     glPixelStore state is set.  It saves and restores the
     pixel store state just to be safe.  It is more efficient
     to put the bitmap calls into a display list because
     the pixel store save and restore is not compiled into
     the display lists (since pixel store state is client
     state). */
  if (updateAll) {
    glNewList(DL_MSG1, GL_COMPILE);
      output(0, 24, "This is written in a GLUT bitmap font.");
    glEndList();
    glNewList(DL_MSG3, GL_COMPILE);
      output(50, 145, "(positioned in pixels with upper-left origin)");
    glEndList();
  }
  glNewList(DL_MSG2, GL_COMPILE);
    output(100, 100, message);
  glEndList();
}

void
selectFont(int newfont)
{
  font = fonts[newfont];
  updateDisplayLists(1);
  glutPostRedisplay();
}

void
selectMessage(int msg)
{
  switch (msg) {
  case 1:
    message = "abcdefghijklmnop";
    break;
  case 2:
    message = "ABCDEFGHIJKLMNOP";
    break;
  }
  updateDisplayLists(0);
  glutPostRedisplay();
}

void
selectColor(int color)
{
  switch (color) {
  case 1:
    glColor3f(0.0, 1.0, 0.0);
    break;
  case 2:
    glColor3f(1.0, 0.0, 0.0);
    break;
  case 3:
    glColor3f(1.0, 1.0, 1.0);
    break;
  }
  glutPostRedisplay();
}

void
display(void)
{
  glClear(GL_COLOR_BUFFER_BIT);
  glCallList(DL_MSG1);
  glCallList(DL_MSG2);
  glCallList(DL_MSG3);
  glutSwapBuffers();
}

void
reshape(int w, int h)
{
  glViewport(0, 0, w, h);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluOrtho2D(0, w, h, 0);
  glMatrixMode(GL_MODELVIEW);
}

void
keyboard(unsigned char c, int x, int y)
{
  switch (c) {
  case 27:
    exit(0);
    break;
  case ' ':
    glutPostRedisplay();
    break;
  }
}

int
main(int argc, char **argv)
{
  int i, msg_submenu, color_submenu;

  glutInit(&argc, argv);
  for (i = 1; i < argc; i++) {
    if (!strcmp(argv[i], "-mono")) {
      font = GLUT_BITMAP_9_BY_15;
    }
  }
  glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
  glutInitWindowSize(1000, 300);
  glutCreateWindow("GLUT bitmap font example");
  glClearColor(0.0, 0.0, 0.0, 1.0);
  glutDisplayFunc(display);
  glutReshapeFunc(reshape);
  glutKeyboardFunc(keyboard);
  msg_submenu = glutCreateMenu(selectMessage);
  glutAddMenuEntry("abc", 1);
  glutAddMenuEntry("ABC", 2);
  color_submenu = glutCreateMenu(selectColor);
  glutAddMenuEntry("Green", 1);
  glutAddMenuEntry("Red", 2);
  glutAddMenuEntry("White", 3);
  glutCreateMenu(selectFont);
  glutAddMenuEntry("9 by 15", 0);
  glutAddMenuEntry("Times Roman 10", 1);
  glutAddMenuEntry("Times Roman 24", 2);
  glutAddSubMenu("Messages", msg_submenu);
  glutAddSubMenu("Color", color_submenu);
  glutAttachMenu(GLUT_RIGHT_BUTTON);
  updateDisplayLists(1);
  glutMainLoop();
  return 0;             /* ANSI C requires main to return int. */
}
